package com.yanqu.road.entity.buildDaoUtil;

import com.yanqu.road.entity.FieldTypeAnnotation;
import com.yanqu.road.entity.activity.apprentice.config.ApprenticeProjectConfig;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.string.StringUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

public class BuildConfigSql {


    public static void main(String[] args) {
        Class<ApprenticeProjectConfig> clz = ApprenticeProjectConfig.class;
        String tableName = "";
        String className = clz.getSimpleName();
        // 获取表名
        if (clz.isAnnotationPresent(FieldTypeAnnotation.class)) {
            tableName = "`" + clz.getAnnotation(FieldTypeAnnotation.class).tableName() + "`";
        }
        
        List<String> orderASCList = new ArrayList<>();
        List<String> orderDESCList = new ArrayList<>();
        List<String> selectList = new ArrayList<>();
        List<String> keyList = new ArrayList<>();
        List<String> keyList1 = new ArrayList<>();
        Field[] fields = clz.getDeclaredFields();
        String fildStr = "";
        for (Field field : fields) {
            if (field.isAnnotationPresent(FieldTypeAnnotation.class)) {
                FieldTypeAnnotation fieldTypeAnnotation = field.getAnnotation(FieldTypeAnnotation.class);
                String fieldName = "`" + field.getName() + "`";
                String fieldDesc = "'" + fieldTypeAnnotation.desc() + "'";
                if (fieldTypeAnnotation.orderASC()) {
                	orderASCList.add(fieldName);
                }
                if (fieldTypeAnnotation.orderDESC()) {
                	orderDESCList.add(fieldName);
                }
                if (fieldTypeAnnotation.select()) {
                    selectList.add(fieldName);
                }
                if (fieldTypeAnnotation.update()) {
                    keyList.add(fieldName);
                    keyList1.add(fieldName);
                }
                if (field.getType() == int.class || field.getType() == boolean.class) {
                    fildStr += "  " + fieldName + " int(11) NOT NULL COMMENT " + fieldDesc + ",\n";
                } else if (field.getType() == long.class) {
                    fildStr += "  " + fieldName + " bigint(20) NOT NULL COMMENT " + fieldDesc + ",\n";
                } else if (field.getType() == Date.class) {
                    fildStr += "  " + fieldName + " datetime NOT NULL COMMENT " + fieldDesc + ",\n";
                } else if (field.getType() == String.class || 
                		field.getType() == List.class || field.getType() == Map.class || 
                		field.getType() == BigInteger.class || field.getType() == BigDecimal.class) {
                    fildStr += "  " + fieldName + " varchar(255) NOT NULL COMMENT " + fieldDesc + ", \n";
                }
            }
        }

        String sql = "CREATE TABLE " + tableName + " (\n" +
                fildStr +
                "  PRIMARY KEY (" + StringUtils.listToString(keyList1, ',') + ")\n" +
                ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;";
        System.out.print(sql);

        
        String params = "";
        String space = "			";
        String buildObject = space + className + " " + toLowerCaseFirstOne(className) + " = new " + className + "();";
        buildObject += "\n";
        for (Field field : fields) {
            if (field.isAnnotationPresent(FieldTypeAnnotation.class)) {
                FieldTypeAnnotation fieldTypeAnnotation = field.getAnnotation(FieldTypeAnnotation.class);
                String fieldName = field.getName();
                String header = toLowerCaseFirstOne(className) + ".set" + toUpperCaseFirstOne(fieldName) + "(";
                String tail = ");\n";
                String sqlGetMethodName = "";

                if (field.getType() == int.class) {
                    sqlGetMethodName = "rs.getInt(\"" + fieldName + "\")";
                    if (fieldTypeAnnotation.select()) {
                    	params = "int " + fieldName + ",";
                    }
                } else if (field.getType() == long.class) {
                    sqlGetMethodName = "rs.getLong(\"" + fieldName + "\")";
                    if (fieldTypeAnnotation.select()) {
                    	params = "long " + fieldName + ",";
                    }
                } else if (field.getType() == short.class) {
                    sqlGetMethodName = "rs.getShort(\"" + fieldName + "\")";
                } else if (field.getType() == boolean.class) {
                    sqlGetMethodName = "rs.getBoolean(\"" + fieldName + "\")";
                } else if (field.getType() == String.class || field.getType() == List.class) {
                    sqlGetMethodName = "rs.getString(\"" + fieldName + "\")";
                } else if (field.getType() == Date.class) {
                    sqlGetMethodName = "rs.getTimestamp(\"" + fieldName + "\")";
                } else if (field.getType() == BigInteger.class) {
                    sqlGetMethodName = "new BigInteger(rs.getString(\"" + fieldName + "\"))";
                } else if (field.getType() == Property.class) {
                    sqlGetMethodName = "PropertyUtils.parseStringToProperty(rs.getString(\"" + fieldName + "\"))";
                }
                buildObject += space + header + sqlGetMethodName + tail;
            }
        }

        buildObject += space + "return " + toLowerCaseFirstOne(className) + ";\n";
        params = params.substring(0, params.length() - 1);

        //System.out.println("select * from " + tableName);
        System.out.println("\n");

        String selectSql = "select * from " + tableName + getWhereCondition(selectList);
        if (!orderASCList.isEmpty() || !orderDESCList.isEmpty()) {
            selectSql += getOrderby(orderASCList, orderDESCList);
        }

        String baseVarName = className + "Sql";
        String selectVarName = "get" + baseVarName;

        System.out.println("	private static String " + selectVarName + " = \"" + selectSql + "\";");
        System.out.println("	public List<" + className + "> get" + className + "List(" + params + ") {\n" +
                "		List<" + className + "> list = new ArrayList<>();\n" +
                "		ResultSet rs = null;\n" +
                "		CallableStatement call = null;\n" +
                "		try {\n" +
                "			getDb().setConnName(DbNameStrategy.getConfigDb());\n" +
                "			call = getDb().getConnection().prepareCall("+ selectVarName + ");\n" +
                "			rs = call.executeQuery();\n" +
                "			while (rs.next()) {\n" + buildObject +
                "			}\n" +
                "		} catch (Exception e) {\n" +
                "			logger.error(Thread.currentThread().getStackTrace()[1].getMethodName() + \":\", e);\n" +
                "		} finally {\n" +
                "			getDb().closeConnection(call, rs);\n" +
                "		}\n" +
                "		return null;\n" +
                "	}\n");
        
        ///////////////////////////////////////////
        String s = "";
        //String varName = clz.getSimpleName().substring(0, 1).toLowerCase() + clz.getSimpleName().substring(1) + ".set";
        for (Field field : fields) {
            // 判断是否被标记
            String fildName = field.getName();
            String fildNamePart1 = fildName.substring(0, 1).toUpperCase();
            String fildNamePart2 = fildName.substring(1);
            String firstUpperName = fildNamePart1 + fildNamePart2;

            if (field.isAnnotationPresent(FieldTypeAnnotation.class)) {
            	if (field.getType() == boolean.class) {
                	s += "	public boolean get" + firstUpperName + "() {\n" +
                            "		return " + fildName + ";\n" +
                            "	}\n";
                    s += "	public void set" + firstUpperName + "(boolean " + fildName + ") {\n" +
                            "		this." + fildName + " = " + fildName + ";\n" +
                            "	}\n\n";
                } else if (field.getType() == int.class) {
                	s += "	public int get" + firstUpperName + "() {\n" +
                            "		return " + fildName + ";\n" +
                            "	}\n";
                    s += "	public void set" + firstUpperName + "(int " + fildName + ") {\n" +
                            "		this." + fildName + " = " + fildName + ";\n" +
                            "	}\n\n";
                } else if (field.getType() == long.class) {
                	s += "	public long get" + firstUpperName + "() {\n" +
                            "		return " + fildName + ";\n" +
                            "	}\n\n";
                    s += "	public void set" + firstUpperName + "(long " + fildName + ") {\n" +
                            "		this." + fildName + " = " + fildName + ";\n" +
                            "	}\n\n";
                } else if (field.getType() == String.class) {
                	s += "	public String get" + firstUpperName + "() {\n" +
                            "		return " + fildName + ";\n" +
                            "	}\n";
                    s += "	public void set" + firstUpperName + "(String " + fildName + ") {\n" +
                            "		this." + fildName + " = " + fildName + ";\n" +
                            "	}\n\n";
                }
            }
        }
        System.out.println("	// ========================================================================");
        System.out.println(s);
    }

    public static <T> String getSelectSql(Class<T> type) {
        Class<T> clz = type;
        String tableName = "";
        // 获取表名
        if (clz.isAnnotationPresent(FieldTypeAnnotation.class)) {
            tableName = "`" + clz.getAnnotation(FieldTypeAnnotation.class).tableName() + "`";
        }

        List<String> orderASCList = new ArrayList<>();
        List<String> orderDESCList = new ArrayList<>();
        List<String> selectList = new ArrayList<>();
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(FieldTypeAnnotation.class)) {
                FieldTypeAnnotation fieldTypeAnnotation = field.getAnnotation(FieldTypeAnnotation.class);
                String fieldName = "`" + field.getName() + "`";
                if (fieldTypeAnnotation.orderASC()) {
                    orderASCList.add(fieldName);
                }
                if (fieldTypeAnnotation.orderDESC()) {
                    orderDESCList.add(fieldName);
                }
                if (fieldTypeAnnotation.select()) {
                    selectList.add(fieldName);
                }
            }
        }

        String selectSql = "select * from " + tableName + getWhereCondition(selectList);
        selectSql += getOrderby(orderASCList, orderDESCList);
        //System.out.println(selectSql);
        return selectSql;
    }

    public static <T> List<String> getKey(Class<T> type) {
        Class<T> clz = type;

        List<String> keyList = new ArrayList<>();
        Field[] fields = clz.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(FieldTypeAnnotation.class)) {
                FieldTypeAnnotation fieldTypeAnnotation = field.getAnnotation(FieldTypeAnnotation.class);
                String fieldName = field.getName();
                if (fieldTypeAnnotation.update()) {
                    keyList.add(fieldName);
                }
            }
        }
        //System.out.println(keyList);
        return keyList;
    }

    public static String getWhereCondition(List<String> list) {
        String sql = "";
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                if (i == 0) {
                    sql += " where ";
                }
                sql += list.get(i) + "=?";
                if (i + 1 < list.size()) {
                    sql += " and ";
                }
            }
        }
        return sql;
    }
    
    public static String getOrderby(List<String> orderASCList, List<String> orderDESCList) {
    	String orderby = "";
    	if (!orderASCList.isEmpty() || !orderDESCList.isEmpty()) {
    		orderby += " ORDER BY ";
    	}
    	if (!orderASCList.isEmpty()) {
    		for (String str : orderASCList) {
    			orderby += str + ",";
    		}
    		orderby = orderby.substring(0, orderby.length() - 1);
    		orderby += " ASC,";
    	}
    	if (!orderDESCList.isEmpty()) {
    		for (String str : orderDESCList) {
    			orderby += str + ",";
    		}
    		orderby = orderby.substring(0, orderby.length() - 1);
    		orderby += " DESC,";
    	}
        if (orderby.length() > 0) {
            orderby = orderby.substring(0, orderby.length() - 1);
        }
    	return orderby;
    }

    //首字母转小写
    public static String toLowerCaseFirstOne(String s){
        if(Character.isLowerCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }


    //首字母转大写
    public static String toUpperCaseFirstOne(String s){
        if(Character.isUpperCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
    }
}
